<!-- MyComponent.vue -->
<template>
  <view class="container">
    <uv-form labelPosition="left" :model="model1" :rules="rules" ref="form">
      <uv-form-item label="数值" prop="datum.val" borderBottom>
        <uv-input v-model="model1.datum.val" border="none"></uv-input>
      </uv-form-item>
      <uv-form-item label="单位" prop="datum.unit" @click="showUnitSelect">
        <uv-input
          v-model="model1.datum.unit"
          disabled
          disabledColor="#ffffff"
          placeholder="请选择单位"
          border="none"
        ></uv-input>
        <template v-slot:right>
          <uv-icon name="arrow-right"></uv-icon>
        </template>
      </uv-form-item>
    </uv-form>
    <uv-divider text="转换结果"></uv-divider>
    <uv-form labelPosition="left" :model="modelResult" ref="convertResult">
      <uv-form-item
        v-for="(item, key) in modelResult"
        :key="key"
        :label="unitNames[key]"
        :prop="key"
        borderBottom
      >
        <uv-input v-model="modelResult[key]" disabled border="none"></uv-input>
      </uv-form-item>
    </uv-form>
    <uv-action-sheet
      ref="uSelect"
      :actions="actions"
      title="请选择单位"
      description=""
      @select="unitSelect"
    ></uv-action-sheet>
  </view>
</template>

<script>
export default {
  name: "CapacityConverter",
  data() {
    return {
      unitNames: {
        ml: "毫升",
        l: "升",
        gal: "加仑",
        qt: "夸脱",
        pt: "品脱",
        cup: "杯",
        floz: "盎司",
        dou: "斗",
        hu: "斛",
        sheng: "升(古)"
      },
      model1: {
        datum: {
          val: "1",
          unit: "毫升"
        }
      },
      modelResult: {
        ml: 0,
        l: 0,
        gal: 0,
        qt: 0,
        pt: 0,
        cup: 0,
        floz: 0,
        dou: 0,
        hu: 0,
        sheng: 0
      },
      actions: [
        { name: "毫升" },
        { name: "升" },
        { name: "加仑" },
        { name: "夸脱" },
        { name: "品脱" },
        { name: "杯" },
        { name: "盎司" },
        { name: "斗" },
        { name: "斛" },
        { name: "升(古)" }
      ],
      rules: {
        "datum.val": {
          type: "number",
          required: true,
          message: "请填写数字"
        }
      }
    }
  },
  watch: {
    "model1.datum.val": function (newVal) {
      const find = Object.keys(this.unitNames).find(
        k => this.unitNames[k] == this.model1.datum.unit
      )
      this.convertAll(newVal, find)
    },
    "model1.datum.unit": function (newVal) {
      const find = Object.keys(this.unitNames).find(k => this.unitNames[k] == newVal)
      this.convertAll(this.model1.datum.val, find)
    }
  },
  methods: {
    showUnitSelect() {
      this.$refs.uSelect.open()
      this.hideKeyboard()
    },
    unitSelect(e) {
      this.model1.datum.unit = e.name
    },
    hideKeyboard() {
      uni.hideKeyboard()
    },
    convertAll(value, fromUnit) {
      for (let unitNamesKey in this.unitNames) {
        this.modelResult[unitNamesKey] = this.convertCapacity(value, fromUnit, unitNamesKey)
      }
    },
    convertCapacity(value, fromUnit, toUnit) {
      // 公制单位间转换
      const metricToMetric = {
        ml: { l: 0.001, kl: 0.000001 },
        l: { ml: 1000, kl: 0.001 },
        kl: { ml: 1e6, l: 1000 }
      }

      // 英制单位间转换
      const imperialToImperial = {
        gal: { qt: 4, pt: 8, cup: 16, floz: 128 },
        qt: { gal: 0.25, pt: 2, cup: 4, floz: 32 },
        pt: { gal: 0.125, qt: 0.5, cup: 2, floz: 16 },
        cup: { gal: 0.0625, qt: 0.25, pt: 0.5, floz: 8 },
        floz: { gal: 0.0078125, qt: 0.03125, pt: 0.015625, cup: 0.125 }
      }

      // 公制与英制单位转换
      const metricToImperial = {
        ml: { gal: 0.00454609, qt: 0.00113652, pt: 0.000568261, cup: 0.000284131, floz: 0.033814 },
        l: { gal: 0.264172, qt: 0.660417, pt: 0.330208, cup: 0.165104, floz: 33.814 },
        kl: { gal: 264.172, qt: 660.417, pt: 330.208, cup: 165.104, floz: 33814 }
      }

      const imperialToMetric = {
        gal: { ml: 3785.41, l: 3.78541, kl: 0.00378541 },
        qt: { ml: 946.353, l: 0.946353, kl: 0.000946353 },
        pt: { ml: 473.176, l: 0.473176, kl: 0.000473176 },
        cup: { ml: 236.588, l: 0.236588, kl: 0.000236588 },
        floz: { ml: 29.5735, l: 0.0295735, kl: 0.0000295735 }
      }

      // 中国古代容量单位转换到公制
      const traditionalToMetric = {
        dou: { ml: 10000, l: 10 }, // 假定1斗=10升
        hu: { ml: 100000, l: 100 }, // 假定1斛=10斗
        sheng: { ml: 1000, l: 1 } // 假定1升=1000毫升
      }

      // 公制转中国古代容量单位
      const metricToTraditional = {
        ml: { dou: 0.001, hu: 0.0001, sheng: 0.001 },
        l: { dou: 0.1, hu: 0.01, sheng: 1 }
      }

      let result

      if (fromUnit in metricToMetric && toUnit in metricToMetric) {
        result = value * metricToMetric[fromUnit][toUnit]
      } else if (fromUnit in imperialToImperial && toUnit in imperialToImperial) {
        result = value * imperialToImperial[fromUnit][toUnit]
      } else if (fromUnit in metricToImperial && toUnit in imperialToMetric) {
        result = value * metricToImperial[fromUnit][toUnit]
      } else if (fromUnit in imperialToMetric && toUnit in metricToImperial) {
        result = value * imperialToMetric[fromUnit][toUnit]
      } else if (fromUnit in traditionalToMetric && toUnit in metricToMetric) {
        result = value * traditionalToMetric[fromUnit][toUnit]
      } else if (fromUnit in metricToTraditional && toUnit in traditionalToMetric) {
        result = value * metricToTraditional[fromUnit][toUnit]
      } else {
        throw new Error("Unsupported conversion between " + fromUnit + " and " + toUnit)
      }

      return result
    }
  }
}
</script>

<style scoped>
.my-component {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background-color: #f0f0f0;
}

button {
  margin-top: 10px;
  padding: 5px 10px;
  border-radius: 5px;
  background-color: #007aff;
  color: white;
}

.container {
  padding: 0 15px;
}
</style>
